{-# OPTIONS -Wall #-}

--------------------------------------------------------------------------------
-- |
-- Module      :  HydroConfig
-- Copyright   :  (c) Stephen Tetley 2014
-- License     :  BSD3
--
-- Maintainer  :  stephen.tetley@gmail.com
-- Stability   :  unstable
-- Portability :  GHC
--
-- Representation of pump sensors - i.e. HydroRangers.
-- 
--------------------------------------------------------------------------------

module HydroConfig
  ( 

  -- * Datatypes
    Decimal
  , Meters
  , HydroConfig(..)
  , Sensor(..)
  , SensorType(..)
  , Unit(..)
  , Mode(..)
  , Material(..)
  , Relays
  , Relay(..)
  , RelayFunction(..)

  -- Helpers
  , makeRelays

  -- * Projectors and misc. functions
  , relaysFrom111
  , relaysFrom008
  , relayCount
  , relayList
  , mbSetpoints

  ) where

import ConfigCheck.Checker

import Data.Fixed
import qualified Data.IntMap as IM

type Decimal = Fixed E9 
type Meters = Decimal


data HydroConfig = HydroConfig
    { site_name         :: String
    , monitored_asset   :: String
    , sensor            :: Sensor
    }
  deriving (Eq,Show)


instance GetName HydroConfig where getName = site_name

-- Note - original_units is setting in HydroRanger, all 
-- measurements are expected to be normalized to meters during
-- /construction/.
-- 
data Sensor = Sensor
    { sensor_type               :: SensorType
    , sensor_mode               :: Mode
    , sensor_material           :: Maybe Material       -- only later Hydros
    , sensor_original_units     :: Unit
    , sensor_empty_distance     :: Meters
    , sensor_span               :: Meters
    , sensor_relays             :: Relays
    }
  deriving (Eq,Show)

data SensorType = HYDRORANGER | HYDRORANGER_200 | HYDRORANGER_PLUS
                | MULTIRANGER | MULTIRANGER_200 | MULTIRANGER_PLUS
                | SENSOR_UNRECOGNIZED
  deriving (Eq,Ord,Show)

data Mode = MODE_LEVEL | MODE_OTHER Int
  deriving (Eq,Show)

data Material = MATERIAL_LIQUID | MATERIAL_SOLID
  deriving (Eq,Ord,Show)


data Unit = UNIT_METERS | UNIT_CENTIMETERS | UNIT_FEET | UNIT_INCHES
          | UNIT_METERS_P | UNIT_CENTIMETERS_P | UNIT_FEET_P | UNIT_INCHES_P
  deriving (Eq,Show)


type Relays = IM.IntMap Relay


data Relay = UncalibRelay { relay_function      :: RelayFunction }
           | CalibRelay   { relay_function      :: RelayFunction
                          , relay_on_setpoint   :: Meters
                          , relay_off_setpoint  :: Meters
                          }
  deriving (Eq,Show)

                                                -- H200 Hy        
data RelayFunction = RELAY_NOT_IN_USE           
                   | RELAY_LEVEL_ALARM          -- 1  
                   | RELAY_LOSS_OF_ECHO         -- 6    7
                   | RELAY_PUMP_EFFICIENCY      -- 8
                   | RELAY_FIXED_DUTY_ASSIST    -- 50   (dE/En):8
                   | RELAY_FIXED_DUTY_BACKUP    -- 51
                   | RELAY_ALT_DUTY_ASSIST      -- 52   (dE/En):9
                   | RELAY_ALT_DUTY_BACKUP      -- 53   (dE/En):'9
                   | RELAY_OTHER       String
  deriving (Eq,Show)




makeRelays :: [(Int,Relay)] -> Relays
makeRelays = IM.fromList




--------------------------------------------------------------------------------
-- Projectors and misc functions

relaysFrom111 :: SensorType -> Bool
relaysFrom111 HYDRORANGER           = False
relaysFrom111 HYDRORANGER_200       = True
relaysFrom111 HYDRORANGER_PLUS      = True
relaysFrom111 MULTIRANGER           = False   -- unknown?
relaysFrom111 MULTIRANGER_200       = True
relaysFrom111 MULTIRANGER_PLUS      = False
relaysFrom111 SENSOR_UNRECOGNIZED   = False

relaysFrom008 :: SensorType -> Bool
relaysFrom008 HYDRORANGER           = True
relaysFrom008 HYDRORANGER_200       = False
relaysFrom008 HYDRORANGER_PLUS      = False
relaysFrom008 MULTIRANGER           = True   -- unknown?
relaysFrom008 MULTIRANGER_200       = False
relaysFrom008 MULTIRANGER_PLUS      = True
relaysFrom008 SENSOR_UNRECOGNIZED   = False


relayCount :: SensorType -> Int
relayCount HYDRORANGER           = 5
relayCount HYDRORANGER_200       = 6
relayCount HYDRORANGER_PLUS      = 5
relayCount MULTIRANGER           = 5
relayCount MULTIRANGER_200       = 5
relayCount MULTIRANGER_PLUS      = 5
relayCount SENSOR_UNRECOGNIZED   = 5


relayList :: Sensor -> [Relay]
relayList (Sensor { sensor_relays = r }) = IM.elems r

-- | It seems reasonable to define this projector, we would
-- probably want it if we were writing in a direct style.
--
mbSetpoints :: Relay -> Maybe (Decimal,Decimal)
mbSetpoints (UncalibRelay {})       = Nothing
mbSetpoints (CalibRelay _ onn off)  = Just (onn,off)
